home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
lang
/
mc302
/
cutil
/
ccref.c
next >
Wrap
C/C++ Source or Header
|
1994-03-18
|
8KB
|
336 lines
/*
* Simple 'C' cross reference listing generator
*
* This program generates a line-numbered listing of a 'C' program, with
* A cross reference table of all global symbols showing their definition,
* and any references to them.
*
* The program does minimal parsing of the 'C' code, and as such has the
* following limitations:
*
* - The first time a symbol is encountered outside of a function definition
* is considered to be its definition. This is usually the case, however for
* symbols #defined in external header files etc, which are used in the
* definition of other global entities, the first use is considered the
* definition.
*
* - Local symbols having names which are identical to a global symbol are
* reported as references.
*
* - Symbols not defined in the file which don't have an explict "extern"
* declaration are not reported. To track library functions etc. which
* fall into this catagory, place an "extern int func()" declaration at
* the start of the file.
*
* Copyright 1993-1994 Dave Dunfield
* All rights reserved.
*
* Permission granted for personal (non-commercial) use only.
*
* Compile command: cc ccref -fop
*/
#include <stdio.h>
#define SYMBOLS 500 /* Maximum number of symbols */
#define SYMBOL_POOL 5000 /* String space for symbol storage */
#define REFERENCES 10000 /* Maximum number of references */
/* Symbol table and associated management variables */
char symbol_pool[SYMBOL_POOL], *symbol_names[SYMBOLS];
int references[REFERENCES], ref_list[SYMBOLS], pool_top = 0, name_top = 0,
ref_top = 0;
/* Command line switch variables */
char list = -1, filename[66];
int page_width = 79, page_length = 60, tab_size = 4;
/* Misc. housekeeping variables */
char in_string = 0, in_comment = 0, *optr, pass = 0;
int bracket = 0, line_number, page_number = 0, pcount = 9999;
/* Table of MICRO-C reserved words */
char *reserved_words[] = {
"int", "unsigned", "char", "static", "extern", "register", "struct",
"union", "if", "else", "while", "do", "for", "switch", "case",
"default", "return", "break", "continue", "goto", "sizeof",
"asm", "#define", "#ifdef", "#ifndef", "#else", "#endif",
"#undef", "#forget", 0 }; /* end of table */
/*
* Main program
*/
main(argc, argv)
int argc;
char *argv[];
{
int i, j, k, l;
char buffer[200], symbol[50], *sptr, c, last_def;
FILE *fp;
if(argc < 2)
abort("\nUse: CCREF <filename> [-list p=page_length t=tab_size w=page_width]\n\nCopyright 1993-1994 Dave Dunfield\nAll rights reserved.\n");
sptr = argv[1];
i = j = 0;
do {
if((filename[i++] = c = toupper(*sptr++)) == '.')
j = -1; }
while(c);
if(!j) {
filename[i-1] = '.';
filename[i] = 'C';
filename[i+1] = 0; }
fp = fopen(filename, "rvq");
for(i=2; i < argc; ++i) {
sptr = argv[i];
switch((toupper(*sptr++) << 8) | toupper(*sptr++)) {
case 'W=' : /* Specify page width */
page_width = atoi(sptr);
break;
case 'T=' : /* Specify tab size */
tab_size = atoi(sptr);
break;
case 'P=' : /* Specify page length */
page_length = atoi(sptr);
break;
case '-L' : /* Inhibit line numbered listing */
list = 0;
break;
default:
printf("Invalid argument: %s\n", argv[i]);
exit(-1); } }
again:
line_number = 0;
while(fgets(optr = buffer, sizeof(buffer)-1, fp)) {
++line_number;
if(list && !pass) {
title("Program Listing");
printf("%5u ", line_number);
i = 0;
while(c = *optr++) {
if(c == '\t') { /* tab */
if((i + tab_size) > (page_width - 6)) {
putc('\n', stdout);
title("Program Listing");
printf(" ");
i = 0; }
do
putc(' ', stdout);
while(++i % tab_size); }
else {
if(++i > (page_width - 6)) {
putc('\n', stdout);
title("Program Listing");
printf(" ");
i = 0; }
putc(c, stdout); } }
putc('\n', stdout);
optr = buffer; }
if(strbeg(buffer, "#include"))
continue;
do {
if(in_string) switch(c = *optr) {
default:
if(c == in_string)
in_string = 0;
continue;;
case '\\' :
++optr;
continue; }
if(in_comment) switch(c = *optr) {
case '/' :
if(*(optr+1) == '*') {
++optr;
++in_comment; }
continue;
case '*' :
if(*(optr+1) == '/') {
++optr;
--in_comment; }
default:
continue; }
switch(c = *optr) {
case '{' :
++bracket;
continue;
case '}' :
--bracket;
continue;
case '/' :
if(*(optr+1) == '*') {
in_comment = 1;
++optr; }
continue;
case '(' :
if(last_def == 1) {
in_string = '{';
++bracket; }
continue;
case '\'' :
case '\"' :
in_string = c;
continue;
case ' ' :
case '\t' :
continue; }
last_def = 0;
if(issymbol(c)) {
sptr = symbol;
while(issymbol(*optr) || isdigit(*optr))
*sptr++ = *optr++;
*sptr = 0;
--optr;
for(i=0; sptr = reserved_words[i]; ++i)
if(!strcmp(symbol, sptr))
goto skip_symbol;
if(bracket) {
if(pass)
reference(symbol); }
else {
if(!pass)
define(symbol);
last_def = 1; }
skip_symbol: } }
while(*optr++); }
if(!pass) {
pass = 1;
rewind(fp);
ref_list[name_top] = ref_top;
goto again; }
fclose(fp);
pcount = 9999;
title("Cross Reference");
printf(" Symbol Def References\n");
title("Cross Reference");
printf("--------------- ----- ");
for(l=22; l < page_width; ++l)
putc('-', stdout);
putc('\n', stdout);
for(;;) {
i = 0;
while(!symbol_names[i])
if(++i >= name_top)
return;
for(j=i+1; j < name_top; ++j)
if((sptr = symbol_names[j]) && (strcmp(sptr, symbol_names[i]) < 0))
i = j;
title("Cross Reference");
printf("%-15s %-5u", symbol_names[i], references[j = ref_list[i]]);
k = ref_list[i+1]-1;
l = 0;
while(j < k) {
if((l += 6) > (page_width-21)) {
l = 6;
printf("\n%-21s", ""); }
printf(" %5u", references[++j]); }
putc('\n', stdout);
symbol_names[i] = 0; }
}
/*
* Test for valid 'C' symbol character.
* Also allow '#', so that we can detect '#' directives. This should
* not conflict with 'C' source since '#' is otherwise not permitted.
*/
issymbol(c)
int c;
{
return ((c >= 'a') && (c <= 'z'))
|| ((c >= 'A') && (c <= 'Z'))
|| (c == '_')
|| (c == '#');
}
/*
* Lookup a symbol in the symbol table
*/
lookup(symbol)
char *symbol;
{
int i;
for(i=0; i < name_top; ++i)
if(!strcmp(symbol_names[i], symbol))
return i;
return -1;
}
/*
* Log a symbol reference
*/
reference(symbol)
char *symbol;
{
int s, i, j;
/* Check that symbol defined */
if((s = lookup(symbol)) == -1)
return;
/* Check that line not already reported */
j = ref_list[s+1];
for(i=ref_list[s]+1; i < j; ++i)
if(references[i] == line_number)
return;
/* Expand reference list to include new number */
if(ref_top >= REFERENCES)
error("Reference table full");
for(i = ref_top++; i > j; --i)
references[i] = references[i-1];
/* Adjust other symbols */
for(i=s+1; i <= name_top; ++i)
++ref_list[i];
references[j] = line_number;
}
/*
* Define a new symbol
*/
define(symbol)
char *symbol;
{
if(lookup(symbol) != -1) {
reference(symbol);
return; }
if(name_top >= SYMBOLS)
error("Symbol table full");
symbol_names[name_top] = &symbol_pool[pool_top];
ref_list[name_top++] = ref_top;
do {
if(pool_top >= SYMBOL_POOL)
error("Symbol name space exausted");
symbol_pool[pool_top++] = *symbol; }
while(*symbol++);
references[ref_top++] = line_number;
}
/*
* Write title for page
*/
title(string)
char *string;
{
if(++pcount >= page_length) {
if(page_number)
putc('\f', stdout);
printf("%-30s %-30s Page: %u\n\n", filename, string, ++page_number);
pcount = 2; }
}
/*
* Report an error in the file
*/
error(string)
char *string;
{
fprintf(stdout, "Error in line %u : %s\n", line_number, string);
exit(-1);
}